
import {firstFocusable} from "./focusable.js";
import {$} from "../util/seq.js";
import {setTabindex} from "./inert.js";
import {hoist} from "./util.js";

/**
 * Defines a roving tab index where the tabbable element is the one that receives focus.
 *
 * @param elements d3 selection of elements that share a roving tabindex
 */
export function defineRovingTabindexByFocus(elements) {

    const nodes = elements.nodes();

    function updateDOM(node) {
        setTabindex(elements, function() { return node === this ? 0 : -1; });
    }

    updateDOM(firstFocusable(nodes) ?? nodes[0]);  // initialize
    elements.on($`focus`, hoist(updateDOM));
}

/**
 * Defines a roving tab index where the tabbable element is the one matching the name in the backing store.
 *
 * @param elements d3 selection of elements that share a roving tabindex
 * @param {Handle} handle the backing store containing the name of the tabbable element
 */
export function defineRovingTabindexByHandle(elements, handle) {

    const nodes = elements.nodes();

    function updateDOM(name) {
        let node = firstFocusable(nodes) ?? nodes[0];  // fallback to the first element if there is no name match
        elements.each(function() { node = (name === this.dataset.name) ? this : node; });
        setTabindex(elements, function() { return node === this ? 0 : -1; });
    }

    updateDOM(handle.get());  // initialize
    handle.on($`change`, updateDOM);
}
